package org.sql.jdbc.datasource;

import java.lang.reflect.Field;
import java.util.Map;

import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;

/** 
 * 根据当前上下文取得数据源。
 * 
 * Spring配置， 可以配置多个数据源。
 * 
 * <pre>
 * <bean id="dataSource" class="com.lc.ibps.base.db.datasource.DynamicDataSource">
 * 	<property name="targetDataSources">
 * 		<map key-type="java.lang.String">
 * 			<entry key="1" value-ref="ds1" />
 * 			<entry key="2" value-ref="ds2" />
 * 		&lt;/map>
 * 	&lt;/property>
 * 	<property name="defaultTargetDataSource" ref="ds1" />
 * &lt;/bean>
 * </pre>
 *
 * <pre> 
 * 构建组：e-jdbc
 * 作者：eddy
 * 邮箱：1546077710@qq.com
 * 日期：2017年4月25日-下午10:21:32
 * 版权：E源时代
 * </pre>
 */
public class DynamicDataSource extends AbstractRoutingDataSource {

	/**
	 * 取得当前使用那个数据源。
	 */
	@Override
	protected Object determineCurrentLookupKey() {
		return DbContextHolder.getDataSource();
	}

	@Override
	public void setTargetDataSources(Map<Object, Object> targetDataSources) {
		super.setTargetDataSources(targetDataSources);
		super.afterPropertiesSet();
	}

	@Override
	public void setDefaultTargetDataSource(Object defaultTargetDataSource) {
		super.setDefaultTargetDataSource(defaultTargetDataSource);
		DbContextHolder.setDefaultDataSource();
	}

	/**
	 * 获取指定实例对象的值
	 * 
	 * @param instance
	 *            实例对象
	 * @param fieldName
	 * @return
	 */
	private static Object getValue(Object instance, String fieldName) {
		Field field = null;
		try {
			field = AbstractRoutingDataSource.class.getDeclaredField(fieldName);
		} catch (NoSuchFieldException e) {
			e.printStackTrace();
		} catch (SecurityException e) {
			e.printStackTrace();
		}
		// 参数值为true，禁用访问控制检查
		field.setAccessible(true);
		try {
			return field.get(instance);
		} catch (IllegalArgumentException e) {
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		}
		return field;
	}

	/**
	 * 添加数据源。
	 * 
	 * @param key
	 * @param dataSource
	 */
	public void add(String key, Object dataSource) {
		Map<Object, Object> targetDataSources = this.get();
		boolean rtn = this.isExist(key);
		if (rtn)
			throw new RuntimeException("DataSource name :" + key
					+ " is exists!");
		targetDataSources.put(key, dataSource);
		super.setTargetDataSources(targetDataSources);
		/**
		 * 这个必须，把数据源从targetDataSources中 加载到 resolvedDataSources属性中。才能实现切换
		 * 
		 */
		super.afterPropertiesSet();
	}

	/**
	 * 指定数据源是否存在。
	 * 
	 * @param key
	 * @return
	 */
	public boolean isExist(String key) {
		return this.get().containsKey(key);
	}

	/**
	 * 根据别名删除数据源。
	 * 
	 * @param key
	 * @throws IllegalAccessException
	 * @throws NoSuchFieldException
	 *             void
	 */
	public void remove(String key) {
		//默认数据源不能移除
		if (key.equals(DataSourceUtil.GLOBAL_DATASOURCE) || key.equals(DataSourceUtil.DEFAULT_DATASOURCE)) {
			throw new RuntimeException("datasource name :" + key
					+ " can't be removed!");
		}
		Map<Object, Object> targetDataSources = this.get();
		targetDataSources.remove(key);
		super.setTargetDataSources(targetDataSources);
	}

	/**
	 * 返回当前有哪些数据源。
	 * 
	 * @return
	 * @throws IllegalAccessException
	 * @throws NoSuchFieldException
	 *             Map<Object,Object>
	 */
	@SuppressWarnings("unchecked")
	public Map<Object, Object> get() {
		return (Map<Object, Object>) getValue(this, DataSourceUtil.TARGET_DATASOURCES);
	}

	public Object getByKey(String key) {
		Map<Object, Object> targetDataSources = this.get();
		return targetDataSources.get(key);
	}
}
